package com.love.common.core.utils.snow;

/**
 * 雪花算法
 */
public class SnowflakeIdGenerator {
    private final long workerId;
    private final long datacenterId;
    private long sequence = 0L;
    private long lastTimestamp = -1L;

    // 常量定义（与之前一致）
    private static final long START_TIMESTAMP = 1617264000000L; // 2021-04-01 00:00:00
    private static final long WORKER_ID_BITS = 10L;
    private static final long DATACENTER_ID_BITS = 5L;
    private static final long SEQUENCE_BITS = 12L;
    private static final long WORKER_ID_MAX = -1L ^ (-1L << WORKER_ID_BITS);
    private static final long DATACENTER_ID_MAX = -1L ^ (-1L << DATACENTER_ID_BITS);
    private static final long SEQUENCE_MAX = -1L ^ (-1L << SEQUENCE_BITS);

    // ========== 构造方法 ==========
    /**
     * 无参构造：使用默认的 workerId=1，datacenterId=1
     */
    public SnowflakeIdGenerator() {
        this.workerId = 1;
        this.datacenterId = 1;
    }

    /**
     * 有参构造：业务模块手动指定 workerId 和 datacenterId
     */
    public SnowflakeIdGenerator(long workerId, long datacenterId) {
        // 校验 ID 合法性
        if (workerId < 0 || workerId > WORKER_ID_MAX) {
            throw new IllegalArgumentException("Worker ID 必须在 0~" + WORKER_ID_MAX + " 之间");
        }
        if (datacenterId < 0 || datacenterId > DATACENTER_ID_MAX) {
            throw new IllegalArgumentException("DataCenter ID 必须在 0~" + DATACENTER_ID_MAX + " 之间");
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
    }

    // ========== 生成 ID 的核心方法 ==========
    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();

        // 1. 时钟回拨检测
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("时钟回拨，拒绝生成 ID");
        }

        // 2. 同一毫秒内，序列号自增
        if (timestamp == lastTimestamp) {
            sequence = (sequence + 1) & SEQUENCE_MAX;
            if (sequence == 0) { // 序列号溢出，等待下一毫秒
                timestamp = waitNextMillis(lastTimestamp);
            }
        } else {
            sequence = 0; // 不同毫秒，序列号重置为 0
        }

        lastTimestamp = timestamp;

        // 3. 位运算组合各部分生成 ID
        return ((timestamp - START_TIMESTAMP) << (WORKER_ID_BITS + DATACENTER_ID_BITS)) |
                (workerId << SEQUENCE_BITS) |
                sequence;
    }

    // 辅助方法：等待到下一毫秒
    private long waitNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}
